//////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//////////////////////////////////////////////////////////////////////
#include "otpch.h"

#include <string>
#include <fstream>
#include <utility>

#include <boost/config.hpp>
#include <boost/version.hpp>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "commands.h"
#include "player.h"
#include "npc.h"
#include "monsters.h"
#include "game.h"
#include "actions.h"
#include "house.h"
#include "iologindata.h"
#include "tools.h"
#include "configmanager.h"
#include "town.h"
#include "spells.h"
#include "talkaction.h"
#include "movement.h"
#include "spells.h"
#include "weapons.h"
#include "raids.h"
#include "chat.h"
#include "status.h"
#include "ioban.h"
#include "textlogger.h"
#include "teleport.h"
#include "const.h"
#include "configserver.h"

#ifdef __ENABLE_SERVER_DIAGNOSTIC__
#include "outputmessage.h"
#include "connection.h"
#include "admin.h"
#include "protocollogin.h"
#include "protocolold.h"
#endif


extern ConfigManager g_config;
extern Actions* g_actions;
extern Monsters g_monsters;
extern Npcs g_npcs;
extern TalkActions* g_talkActions;
extern MoveEvents* g_moveEvents;
extern Spells* g_spells;
extern Weapons* g_weapons;
extern Game g_game;
extern Chat g_chat;
extern CreatureEvents* g_creatureEvents;

s_defcommands Commands::defined_commands[] =
{
	{"/addskill", &Commands::addSkill},
	{"/attr", &Commands::thingProporties},
	#ifdef __ENABLE_SERVER_DIAGNOSTIC__
	{"/serverdiag", &Commands::diagnostics},
	#endif
	{"/pvp", &Commands::setWorldType},
	{"/premium", &Commands::addPlayerPremium},
	{"/openserver", &Commands::openServer},
	{"/closeserver", &Commands::closeServer},
	{"/i", &Commands::createItemById},
	{"/n", &Commands::createItemByName},
	{"/B", &Commands::broadcastMessage},
	{"/bc", &Commands::broadcastClass},
	{"/s", &Commands::placeNpc},
	{"/m", &Commands::placeMonster},
	{"/summon", &Commands::placeSummon},
	{"/clean", &Commands::cleanMap},
	{"/ghost", &Commands::ghostCommand},
	{"/mc", &Commands::multiClientCheck},
	{"/kick", &Commands::kickCommand},
	{"/newtype", &Commands::commandNewType},
	{"/z",&Commands::testCommand},
	{"/zt",&Commands::testTutorialCommand},

	{"!crystal", &Commands::creatorServer},
	{"!exp", &Commands::showExpForLevel},
	{"!mana", &Commands::showManaForLevel},
	{"!serverinfo", &Commands::serverInfo},
	{"!pvp", &Commands::pvpInformation},
	{"!q", &Commands::checkMoney},
	{"!uptime", &Commands::showWorldUpTime},
	{"!notice", &Commands::showNotices},
	{"!online", &Commands::whoIsOnline},

	{"!createguild", &Commands::guildCreate},
	{"!joinguild", &Commands::guildJoin},

};

Commands::Commands()
{
	loaded = false;

	//setup command map
	for(uint32_t i = 0; i < sizeof(defined_commands) / sizeof(defined_commands[0]); i++){
		Command* cmd = new Command;
		cmd->loaded = false;
		cmd->accesslevel = 1;
		cmd->f = defined_commands[i].f;
		std::string key = defined_commands[i].name;
		commandMap[key] = cmd;
	}
}

bool Commands::loadFromXml()
{
	std::string strValue;
	xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_XML, "commands.xml").c_str());
	if(doc)
	{
		loaded = true;
		xmlNodePtr root, p;
		root = xmlDocGetRootElement(doc);

		if(xmlStrcmp(root->name,(const xmlChar*)"commands") != 0)
		{
			xmlFreeDoc(doc);
			return false;
		}

		std::string strCmd;
		p = root->children;

		while (p){
			if(xmlStrcmp(p->name, (const xmlChar*)"command") == 0){
				if(readXMLString(p, "cmd", strCmd))
				{
					CommandMap::iterator it = commandMap.find(strCmd);
					int alevel;
					if(it != commandMap.end()){
						if(readXMLInteger(p,"access",alevel)){
							if(!it->second->loaded){
								it->second->accesslevel = alevel;
								it->second->loaded = true;
							}
							else{
								std::cout << ":: Duplicated command " << strCmd << std::endl;
							}
						}
						else{
							std::cout << ":: missing access tag for " << strCmd << std::endl;
						}
					}
					else{
						//error
						std::cout << ":: Unknown command " << strCmd << std::endl;
					}
				}
				else{
					std::cout << ":: missing cmd." << std::endl;
				}
			}
			p = p->next;
		}
		xmlFreeDoc(doc);
	}

	//
	for(CommandMap::iterator it = commandMap.begin(); it != commandMap.end(); ++it){
		if(it->second->loaded == false){
			std::cout << "Warning: Missing access level for command " << it->first << std::endl;
		}
		//register command tag in game
		g_game.addCommandTag(it->first.substr(0,1));
	}


	return this->loaded;
}

bool Commands::reload()
{
	this->loaded = false;
	for(CommandMap::iterator it = commandMap.begin(); it != commandMap.end(); ++it)
	{
		it->second->accesslevel = 1;
		it->second->loaded = false;
	}
	g_game.resetCommandTag();
	return loadFromXml();
}

bool Commands::exeCommand(Creature* creature, const std::string& cmd)
{
	std::string str_command;
	std::string str_param;

	std::string::size_type loc = cmd.find( ' ', 0 );
	if(loc != std::string::npos && loc >= 0)
	{
		str_command = std::string(cmd, 0, loc);
		str_param = std::string(cmd, (loc + 1), cmd.size() - loc - 1);
	}
	else
	{
		str_command = cmd;
		str_param = std::string("");
	}

	//find command
	CommandMap::iterator it = commandMap.find(str_command);
	if(it == commandMap.end())
		return false;

	Player* player = creature->getPlayer();
	if(player && player->getAccess() < it->second->accesslevel)
	{
		if(player->getAccess() > 0)
		{
			player->sendTextMessage(MSG_STATUS_SMALL, "You can not execute this command.");
		}

		return false;
	}

	//execute command
	CommandFunc cfunc = it->second->f;
	(this->*cfunc)(creature, str_command, str_param);
	if(player)
	{
	 	if(player->getAccess() > 0)
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_RED, cmd.c_str());
			Logger::getInstance()->eFile("commands/" + creature->getName() + ".log", cmd, true);
		}
	}
	return true;
}

bool Commands::addSkill(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	StringVec params = explodeString(param, ",");
	if(params.size() < 2)
	{
		player->sendTextMessage(MSG_STATUS_SMALL, "Command requires at least 2 parameters.");
		return true;
	}

	uint32_t amount = 1;
	if(params.size() > 2)
	{
		std::string tmp = params[2];
		trimString(tmp);
		amount = (uint32_t)std::max(1, atoi(tmp.c_str()));
	}

	std::string name = params[0], skill = params[1];
	trimString(name);
	trimString(skill);

	Player* target = NULL;
	ReturnValue ret = g_game.getPlayerByNameWildcard(name, target);
	if(ret != RET_NOERROR)
	{
		player->sendCancelMessage(ret);
		return true;
	}

	if(skill[0] == 'l' || skill[0] == 'e')
		target->addExperience(uint64_t(Player::getExpForLevel(target->getLevel() + amount) - target->getExperience()));
	else if(skill[0] == 'm')
		target->addManaSpent((uint64_t)(target->getVocation()->getReqMana(target->getMagicLevel() +
			amount) - target->getSpentMana()), false);
	else
	{
		skills_t skillId = getSkillId(skill);
		target->addSkillAdvance(skillId, (uint32_t)(target->getVocation()->getReqSkillTries(skillId, target->getSkill(skillId,
			SKILL_LEVEL) + amount) - target->getSkill(skillId, SKILL_TRIES)), false);
	}

	return true;
}

bool Commands::thingProporties(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	const Position& pos = getNextPosition(player->getDirection(), player->getPosition());
	Tile* tile = g_game.getTile(pos);
	if(!tile)
	{
		player->sendTextMessage(MSG_STATUS_SMALL, "No tile found.");
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return true;
	}

	Thing* thing = tile->getTopVisibleThing(creature);
	if(!thing)
	{
		player->sendTextMessage(MSG_STATUS_SMALL, "No object found.");
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		return true;
	}

	boost::char_separator<char> sep(" ");
	tokenizer tokens(param, sep);

	std::string invalid;
	for(tokenizer::iterator it = tokens.begin(); it != tokens.end();)
	{
		std::string action = parseParams(it, tokens.end());
		toLowerCaseString(action);
		if(Item* item = thing->getItem())
		{
			if(action == "set")
			{
				std::string key = parseParams(it, tokens.end()), value = parseParams(it, tokens.end());
				if(atoi(value.c_str()) || value == "0")
					item->setAttribute(key, atoi(value.c_str()));
				else
					item->setAttribute(key, value);
			}
			else if(action == "erase" || action == "remove")
				item->eraseAttribute(parseParams(it, tokens.end()));
			else if(action == "action" || action == "actionid" || action == "aid")
			{
				int32_t tmp = atoi(parseParams(it, tokens.end()).c_str());
				if(tmp > 0)
					item->setActionId(tmp);
				else
					item->resetActionId();
			}
			else if(action == "unique" || action == "uniqueid" || action == "uid")
			{
				int32_t tmp = atoi(parseParams(it, tokens.end()).c_str());
				if(tmp >= 1000 || tmp <= 0xFFFF)
					item->setUniqueId(tmp);
			}
			else if(action == "destination" || action == "position"
				|| action == "pos" || action == "dest") //TODO: doesn't work
			{
				if(Teleport* teleport = item->getTeleport())
					teleport->setDestination(Position(atoi(parseParams(it,
						tokens.end()).c_str()), atoi(parseParams(it, tokens.end()).c_str()),
						atoi(parseParams(it, tokens.end()).c_str())));
			}
			else
			{
				std::stringstream s;
				s << action << " (" << parseParams(it, tokens.end()) << ")";
				invalid += s.str();
				break;
			}
		}
		else if(Creature* _creature = thing->getCreature())
		{
			if(action == "health")
				_creature->changeHealth(atoi(parseParams(it, tokens.end()).c_str()));
			else if(action == "maxhealth")
				_creature->changeMaxHealth(atoi(parseParams(it, tokens.end()).c_str()));
			else if(action == "mana")
				_creature->changeMana(atoi(parseParams(it, tokens.end()).c_str()));
			else if(action == "maxmana")
				_creature->changeMaxMana(atoi(parseParams(it, tokens.end()).c_str()));
			else if(action == "basespeed")
				_creature->setBaseSpeed(atoi(parseParams(it, tokens.end()).c_str()));
			else if(action == "droploot")
				_creature->setDropLoot((lootDrop_t)atoi(parseParams(it, tokens.end()).c_str()));
			else if(action == "lossskill")
				_creature->setLossSkill(booleanString(parseParams(it, tokens.end())));
			else if(action == "cannotmove")
				_creature->setNoMove(booleanString(parseParams(it, tokens.end())));
			else if(action == "skull")
			{
				_creature->setSkull(getSkull(parseParams(it, tokens.end())));
				g_game.updateCreatureSkull(_creature);
			}
			else if(action == "speaktype")
				_creature->setSpeakType((SpeakClasses)atoi(parseParams(it, tokens.end()).c_str()));
			else if(Player* _player = _creature->getPlayer())
			{
				if(action == "fyi")
					_player->sendFYIBox(parseParams(it, tokens.end()).c_str());
				else if(action == "tutorial")
					_player->sendTutorial(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "guildlevel")
					_player->setGuildLevel((GuildLevel_t)atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "guildrank")
					_player->setRankId(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "guildnick")
					_player->setGuildNick(parseParams(it, tokens.end()).c_str());
				else if(action == "group")
					_player->setGroupId(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "vocation")
					_player->setVocation(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "sex" || action == "gender")
					_player->setSex(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "stamina")
					_player->setStaminaMinutes(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "town" || action == "temple")
				{
					if(Town* town = Towns::getInstance()->getTown(parseParams(it, tokens.end())))
					{
						_player->setMasterPosition(town->getPosition());
						_player->setTown(town->getID());
					}
				}
				else if(action == "balance")
					_player->balance = atoi(parseParams(it, tokens.end()).c_str());
				else if(action == "marriage" || action == "partner")
					_player->marriage = atoi(parseParams(it, tokens.end()).c_str());
				else if(action == "rates")
					_player->rates[atoi(parseParams(it, tokens.end()).c_str())] = atof(
						parseParams(it, tokens.end()).c_str());
				else if(action == "idle")
					_player->setIdleTime(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "capacity" || action == "cap")
					_player->setCapacity(atoi(parseParams(it, tokens.end()).c_str()));
				else if(action == "execute")
					g_talkActions->onPlayerSay(_player, atoi(parseParams(it, tokens.end()).c_str()),
						parseParams(it, tokens.end()), booleanString(parseParams(it, tokens.end())));
				else if(action == "saving" || action == "save")
					_player->switchSaving();
				else
				{
					std::stringstream s;
					s << action << " (" << parseParams(it, tokens.end()) << ")";
					invalid += s.str();
					break;
				}
			}
			else
			{
				std::stringstream s;
				s << action << " (" << parseParams(it, tokens.end()) << ")";
				invalid += s.str();
				break;
			}
		}
	}

	const SpectatorVec& list = g_game.getSpectators(pos);
	SpectatorVec::const_iterator it;

	Player* tmpPlayer = NULL;
	for(it = list.begin(); it != list.end(); ++it)
	{
		if((tmpPlayer = (*it)->getPlayer()))
			tmpPlayer->sendUpdateTile(tile, pos);
	}

	for(it = list.begin(); it != list.end(); ++it)
		(*it)->onUpdateTile(tile, pos);

	g_game.addMagicEffect(pos, MAGIC_EFFECT_WRAPS_GREEN);
	if(invalid.empty())
		return true;

	std::string tmp = "Following action was invalid: " + invalid;
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, tmp.c_str());
	return true;
}

bool Commands::diagnostics(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

#ifdef __ENABLE_SERVER_DIAGNOSTIC__
	std::stringstream text;
	text << "Server diagonostic:\n";
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());

	text.str("");
	text << "World:" << "\n";
	text << "--------------------\n";
	text << "Player: " << g_game.getPlayersOnline() << " (" << Player::playerCount << ")" << std::endl;
	text << "Npc: " << g_game.getNpcsOnline() << " (" << Npc::npcCount << ")" << std::endl;
	text << "Monster: " << g_game.getMonstersOnline() << " (" << Monster::monsterCount << ")" << std::endl << std::endl;
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());

	text.str("");
	text << "Protocols:" << "\n";
	text << "--------------------\n";
	text << "ProtocolGame: " << ProtocolGame::protocolGameCount << std::endl;
	text << "ProtocolLogin: " << ProtocolLogin::protocolLoginCount << std::endl;
#ifdef __REMOTE_CONTROL__
	text << "ProtocolAdmin: " << ProtocolAdmin::protocolAdminCount << std::endl;
#endif
	text << "ProtocolStatus: " << ProtocolStatus::protocolStatusCount << std::endl;
	text << "ProtocolOld: " << ProtocolOld::protocolOldCount << std::endl << std::endl;
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());

	text.str("");
	text << "Connections:\n";
	text << "--------------------\n";
	text << "Active connections: " << Connection::connectionCount << "\n";
	text << "Total message pool: " << OutputMessagePool::getInstance()->getTotalMessageCount() << std::endl;
	text << "Auto message pool: " << OutputMessagePool::getInstance()->getAutoMessageCount() << std::endl;
	text << "Queued message pool: " << OutputMessagePool::getInstance()->getQueuedMessageCount() << std::endl;
	text << "Free message pool: " << OutputMessagePool::getInstance()->getAvailableMessageCount() << std::endl << std::endl;
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());

	text.str("");
	text << "Libraries:\n";
	text << "--------------------\n";
	text << "Platform: " << BOOST_PLATFORM << std::endl;
	text << "Compiler: " << BOOST_COMPILER << std::endl;
	text << "Boost: " << BOOST_VERSION << std::endl;
	text << "ASIO: " << BOOST_ASIO_VERSION << std::endl;
	text << "XML: " << XML_DEFAULT_VERSION << std::endl;
	text << "Lua: " << LUA_VERSION << std::endl;
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());

#endif
	return true;
}

bool Commands::setWorldType(Creature* creature, const std::string &cmd, const std::string &param)
{
	Player* player = creature->getPlayer();

	if(!player)
	{
		return false;
	}	

	    if (player->isRemoved())
		{ 
		    return false; 
	    }
	    
		if(param == "")
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Command requires param.");
		 }

		if(param == "nopvp" || param == "no-pvp" || 
				 param == "non-pvp" || param == "nonpvp" || 
				 param == "safe" || param == "optional" || 
				 param == "optionalpvp" || param == "optional-pvp")
		{
			g_game.setWorldType(WORLD_TYPE_NO_PVP);
			player->sendTextMessage(MSG_STATUS_WARNING, "Gameworld type set to: Optional-PvP.");
		 }
		if(param == "pvp" || param == "normal" || 
				 param == "open" || param == "openpvp" || 
				 param == "open-pvp")
		{
			g_game.setWorldType(WORLD_TYPE_NO_PVP);
			player->sendTextMessage(MSG_STATUS_WARNING, "Gameworld type set to: Open-PvP.");
		 }
		if(param == "enforced" || param == "pvp-enforced" || 
				 param == "pvpe" || param == "pvpenforced" || 
				 param == "war" || param == "hardcore" || 
				 param == "hardcore-pvp" || param == "hardcorepvp")
		{
			g_game.setWorldType(WORLD_TYPE_PVP_ENFORCED);
			player->sendTextMessage(MSG_STATUS_WARNING, "Gameworld type set to: Hardcore-PvP.");
		 }
	return true;
}

bool Commands::addPlayerPremium(Creature* creature, const std::string& cmd, const std::string& param)
{
	uint32_t premiumTime = 0;
	std::string name;
	std::istringstream in(param.c_str());

	std::getline(in, name, ',');
	in >> premiumTime;	
	
	Player* player = g_game.getPlayerByName(name);
	if(player){
		if(premiumTime < 0 || premiumTime > 999)
		{
			premiumTime = 1;
		}
		
	uint32_t days = premiumTime;
	    
     Account account = IOLoginData::getInstance()->loadAccount(player->getAccount());
		if(player->premiumDays < 65535)
		{
			if(player->premiumDays <= 50000 && days <= 10000)
			{
				account.premiumDays += days;
				player->premiumDays += days;
			}
			IOLoginData::getInstance()->saveAccount(account);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE);
			return true;
		}
	}
    
	return false;
}

bool Commands::openServer(Creature* creature, const std::string &cmd, const std::string &param)
{
 	 Player* player = creature->getPlayer();
	if(!player){
		return false;
	}
	
	g_game.setGameState(GAME_STATE_NORMAL);
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Server has been opened successfully.");

	return true;
}

bool Commands::closeServer(Creature* creature, const std::string &cmd, const std::string &param)
{
 	 Player* player = creature->getPlayer();
	if(!player){
		return false;
	}
	
	g_game.setGameState(GAME_STATE_CLOSED);
	
	for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
       if(dynamic_cast<Player*>(it->second))
		if(!(*it).second->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges)){
			(*it).second->kickPlayer(true, true);
		}

	bool payHouses = (param == "serversave");
	g_game.saveGameState(payHouses);
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Server has been closed successfully.");

	return true;
}

bool Commands::createItemById(Creature* creature, const std::string& cmd, const std::string& param)
{

	Player* player = creature->getPlayer();
	if(!player)
		return false;

	std::string tmp = param;
	std::string::size_type pos = tmp.find(' ', 0);
	if(pos == std::string::npos)
	{
		pos = tmp.size();
	}

	int32_t type = atoi(tmp.substr(0, pos).c_str());
	int32_t count = 1;
	if(pos < tmp.size())
	{
		tmp.erase(0, pos+1);
		count = std::max(0, std::min(atoi(tmp.c_str()), 100));
	}

	Item* newItem = Item::CreateItem(type, count);
	if(g_config.getBool(ConfigManager::SHOW_DESCR))
	newItem->setSpecialDescription("This item was made by " + player->getName());
	if(!newItem)
		return false;

	ReturnValue ret = g_game.internalAddItem(NULL, player, newItem);
	if(ret != RET_NOERROR)
	{
			ReturnValue ret = g_game.internalAddItem(NULL, player, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT);

		if(ret != RET_NOERROR)
		{
			delete newItem;
			return false;
		}
	}
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE);
	return true;
}


bool Commands::createItemByName(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	std::string::size_type pos1 = param.find("\"");
	pos1 = (std::string::npos == pos1 ? 0 : pos1 + 1);

	std::string::size_type pos2 = param.rfind("\"");
	if(pos2 == pos1 || pos2 == std::string::npos){
		pos2 = param.rfind(' ');

		if(pos2 == std::string::npos){
			pos2 = param.size();
		}
	}

	std::string itemName = param.substr(pos1, pos2 - pos1);
	int32_t count = 1;
	if(pos2 < param.size())
	{
		std::string itemCount = param.substr(pos2 + 1, param.size() - (pos2 + 1));
		count = std::max(0, std::min(atoi(itemCount.c_str()), 100));
	}

	int32_t itemId = Item::items.getItemIdByName(itemName);
	if(itemId == -1)
	{
		player->sendTextMessage(MSG_STATUS_CONSOLE_RED, "Item could not be created.");
		return false;
	}

	Item* newItem = Item::CreateItem(itemId, count);
	if(g_config.getBool(ConfigManager::SHOW_DESCR))
	newItem->setSpecialDescription("This item was made by " + player->getName());
	if(!newItem)
		return false;

	ReturnValue ret = g_game.internalAddItem(NULL, player, newItem);
	if(ret != RET_NOERROR){
			ReturnValue ret = g_game.internalAddItem(NULL, player, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT);


		if(ret != RET_NOERROR)
		{
			delete newItem;
			return false;
		}
	}
		g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_BLUE);
	return true;
}

bool Commands::broadcastMessage(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;
		
		if(param == "")
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Command requires param.");
		}

	return g_game.gmBroadcastMessage(player, param);
}

bool Commands::broadcastClass(Creature* creature, const std::string &cmd, const std::string &param)
{
    int a;
    int colorInt;
    Player* player = creature->getPlayer();
    std::string message = param.c_str();
    std::stringstream fullMessage;
    std::string color;
    MessageClasses mclass;
    
    for(a=0; a<param.length(); ++a)
	{
       if(param[a] > 3 && param[a] == ' ')
	   {
         color = param;
         color.erase(a,1-param.length());
         message.erase(0,1+a);
         break;
       }
       else
          message = param.c_str();       
    }
    
    std::transform(color.begin(), color.end(), color.begin(), tolower);
    fullMessage << message.c_str() <<std::endl; //Name: Message
    
    if(color == "blue")
       mclass = MSG_STATUS_CONSOLE_BLUE;
    else if(color == "red_warning")
	{
       g_game.gmBroadcastMessage(player, fullMessage.str().c_str());
       return false;
    }
    else if(color == "red")
       mclass = MSG_STATUS_CONSOLE_RED;
    else if(color == "advance")
       mclass = MSG_EVENT_ADVANCE; //Invasion
    else if(color == "event")
       mclass = MSG_EVENT_ADVANCE; //Invasion
    else if(color == "white")
       mclass = MSG_EVENT_DEFAULT;
    else if(color == "green")
       mclass = MSG_INFO_DESCR;
    else if(color == "info")
       mclass = MSG_INFO_DESCR;
    else if(color == "small")
       mclass = MSG_STATUS_SMALL;                                      
    else if(color == "warning")
        mclass = MSG_STATUS_WARNING;
    else if(color == "orange_event")
        mclass = MSG_EVENT_ORANGE;
    else if(color == "orange")
        mclass = MSG_STATUS_CONSOLE_ORANGE;
        
    else{
       player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "The options to colors are: blue, red, advance, event, white, green, info, small, warning, orange and orange_event.");
       return false;
    }
                      
	for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
       if(dynamic_cast<Player*>(it->second))
         (*it).second->sendTextMessage(mclass, fullMessage.str().c_str());
    
    return true;
}

bool Commands::placeNpc(Creature* creature, const std::string& cmd, const std::string& param)
{
	Npc* npc = Npc::createNpc(param);
	if(!npc)
		return false;

	// Place the npc
	if(g_game.placeCreature(npc, creature->getPosition()))
	{
		g_game.addMagicEffect(creature->getPosition(), MAGIC_EFFECT_BLOODYSTEPS);
		npc->setMasterPos(npc->getPosition());
		return true;
	}
	else
	{
		delete npc;
		Player* player = creature->getPlayer();
		if(player)
		{
			player->sendCancelMessage(RET_NOTENOUGHROOM);
			g_game.addMagicEffect(creature->getPosition(), MAGIC_EFFECT_POFF);
		}
		return true;
	}
	return false;
}

bool Commands::placeMonster(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();

	Monster* monster = Monster::createMonster(param);
	if(!monster)
	{
		if(player)
		{
			player->sendCancelMessage(RET_NOTPOSSIBLE);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		}
		return false;
	}

	// Place the monster
	if(g_game.placeCreature(monster, creature->getPosition()))
	{
		g_game.addMagicEffect(creature->getPosition(), MAGIC_EFFECT_BLOODYSTEPS);
		return true;
	}
	else
	{
		delete monster;
		if(player)
		{
			player->sendCancelMessage(RET_NOTENOUGHROOM);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		}
	}

	return false;
}

ReturnValue Commands::placeSummon(Creature* creature, const std::string& name)
{
	Monster* monster = Monster::createMonster(name);
	if(!monster)
	{
		return RET_NOTPOSSIBLE;
	}
	// Place the monster
	creature->addSummon(monster);
	if(!g_game.placeCreature(monster, creature->getPosition()))
	{
		creature->removeSummon(monster);
		return RET_NOTENOUGHROOM;
	}

	return RET_NOERROR;
}

bool Commands::placeSummon(Creature* creature, const std::string& cmd, const std::string& param)
{
	ReturnValue ret = placeSummon(creature, param);

	if(ret != RET_NOERROR)
	{
		if(Player* player = creature->getPlayer())
		{
			player->sendCancelMessage(ret);
			g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		}
	}
	return (ret == RET_NOERROR);
}

bool Commands::cleanMap(Creature* creature, const std::string &cmd, const std::string &param)
{
	uint32_t count = 0;
	g_game.cleanMap(count);
	
	char* buffer = new char[128];
	sprintf(buffer, "Game map cleaned: Cleaned %d items from the map.", count);
	
	for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
       if(dynamic_cast<Player*>(it->second))
         (*it).second->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, std::string(buffer));
	delete [] buffer;
	return true;
}

bool Commands::ghostCommand(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	if(player->hasFlag(PlayerFlag_CannotBeSeen))
	{
		player->sendTextMessage(MSG_INFO_DESCR, "Command disabled for players with special, invisibility flag.");
		return true;
	}

	SpectatorVec::iterator it;
	SpectatorVec list = g_game.getSpectators(player->getPosition());
	Player* tmpPlayer = NULL;

	Condition* condition = NULL;
	if((condition = player->getCondition(CONDITION_GAMEMASTER, CONDITIONID_DEFAULT, GAMEMASTER_INVISIBLE)))
	{
		player->sendTextMessage(MSG_INFO_DESCR, "You are visible again.");
		IOLoginData::getInstance()->updateOnlineStatus(player->getGUID(), true);
		for(AutoList<Player>::iterator pit = Player::autoList.begin(); pit != Player::autoList.end(); ++pit)
		{
			if(!pit->second->canSeeCreature(player))
				pit->second->notifyLogIn(player);
		}

		for(it = list.begin(); it != list.end(); ++it)
		{
			if((tmpPlayer = (*it)->getPlayer()) && !tmpPlayer->canSeeCreature(player))
				tmpPlayer->sendMagicEffect(player->getPosition(), MAGIC_EFFECT_TELEPORT);
		}

		player->removeCondition(condition);
		g_game.internalCreatureChangeVisible(creature, VISIBLE_GHOST_APPEAR);
	}
	else if((condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_GAMEMASTER, -1, 0, false, GAMEMASTER_INVISIBLE)))
	{
		player->addCondition(condition);
		g_game.internalCreatureChangeVisible(creature, VISIBLE_GHOST_DISAPPEAR);
		for(it = list.begin(); it != list.end(); ++it)
		{
			if((tmpPlayer = (*it)->getPlayer()) && !tmpPlayer->canSeeCreature(player))
				tmpPlayer->sendMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);
		}

		for(AutoList<Player>::iterator pit = Player::autoList.begin(); pit != Player::autoList.end(); ++pit)
		{
			if(!pit->second->canSeeCreature(player))
				pit->second->notifyLogOut(player);
		}

		IOLoginData::getInstance()->updateOnlineStatus(player->getGUID(), false);
		if(player->isTrading())
			g_game.internalCloseTrade(player);

		player->clearPartyInvitations();
		if(player->getParty())
			player->getParty()->leave(player);

		player->sendTextMessage(MSG_INFO_DESCR, "You are now invisible.");
	}

	return true;
}

bool Commands::multiClientCheck(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	std::list<uint32_t> ipList;

	std::stringstream text;
	text << "Multiclient List:";
	player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());
	text.str("");

	for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
	{
		if(it->second->isRemoved() || it->second->getIP() == 0 || std::find(ipList.begin(), ipList.end(), it->second->getIP()) != ipList.end())
			continue;

		std::list< std::pair<std::string, uint32_t> > playerList;
		for(AutoList<Player>::iterator it2 = Player::autoList.begin(); it2 != Player::autoList.end(); ++it2)
		{
			if(it->second == it2->second || it2->second->isRemoved())
				continue;

			if(it->second->getIP() == it2->second->getIP())
				playerList.push_back(make_pair(it2->second->getName(), it2->second->getLevel()));
		}

		if(!playerList.empty())
		{
			text << convertIPAddress(it->second->getIP()) << ":\n"
			<< it->second->getName() << " [" << it->second->getLevel() << "], ";
			uint32_t tmp = 0;
			for(std::list< std::pair<std::string, uint32_t> >::const_iterator p = playerList.begin(); p != playerList.end(); p++)
			{
				tmp++;
				if(tmp != playerList.size())
					text << p->first << " [" << p->second << "], ";
				else
					text << p->first << " [" << p->second << "].";
			}

			ipList.push_back(it->second->getIP());
		}

		if(text.str() != "")
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, text.str().c_str());
			text.str("");
		}
	}
	return true;
}

bool Commands::kickCommand(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* playerKick = g_game.getPlayerByName(param);
	if(playerKick)
	{
		Player* player = creature->getPlayer();
		if(player && playerKick->getAccess() > 2)
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "You cannot kick this player.");
			return false;
		}

		playerKick->kickPlayer(true, true);
		return true;
	}
	return false;
}

bool Commands::commandNewType(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(player)
	{
		int32_t lookType = atoi(param.c_str());
		if(lookType >= 0 && lookType != 1 && lookType != 135 && (lookType <= 160 || lookType >= 192) && lookType <= 351)
		{
			g_game.internalCreatureChangeOutfit(creature, (const Outfit_t&)lookType);
			return true;
		}
		else
			player->sendTextMessage(MSG_STATUS_SMALL, "This outfit does not exist.");
	}
	return false;
}

bool Commands::testCommand(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	int32_t effect = atoi(param.c_str());

    if(effect < MAGIC_EFFECT_FIRST || effect > MAGIC_EFFECT_LAST)
        player->sendCancel("Sorry, the effect can be 0 to 68 only.");
        else
		player->sendMagicEffect(player->getPosition(), effect);


	return true;
}

bool Commands::testTutorialCommand(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	int32_t color = atoi(param.c_str());

    if(color < 0 || color > 6)
        player->sendCancel("Sorry, the tutorials test can be 0 to 6 only.");
        else
		player->sendTutorial(color);

	return true;
}

bool Commands::creatorServer(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(player)
	{
		player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, CREATOR_INFO);
	}
	return true;
}

bool Commands::showExpForLevel(Creature* creature, const std::string &cmd, const std::string &param)
{
	if(Player* player = creature->getPlayer()){
		std::stringstream msg;
	msg << "You need " << player->getExpForLevel(player->getLevel() + 1) - player->getExperience() << " experience points to gain level" << std::endl;
		player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, msg.str().c_str());
	}
	
	return true;
}

bool Commands::showManaForLevel(Creature* creature, const std::string &cmd, const std::string &param)
{
	if(Player* player = creature->getPlayer())
	{
               std::stringstream msg;
               msg << "You need to spent " << (long)player->vocation->getReqMana(player->getMagicLevel()+1) - player->getSpentMana() / g_config.getDouble(ConfigManager::RATE_MAGIC) << " mana to gain magic level" << std::endl;
		player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, msg.str().c_str());
	}

	return true;
}

bool Commands::serverInfo(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	std::stringstream text;
	text << "Server Info:";
	text << "\nExp Rate: " << g_game.getExperienceStage(player->level);
	text << "\nExp Rate PVP-E: " << g_config.getDouble(ConfigManager::RATE_PVP_EXPERIENCE);
	text << "\nSkill Rate: " << g_config.getDouble(ConfigManager::RATE_SKILL);
	text << "\nMagic Rate: " << g_config.getDouble(ConfigManager::RATE_MAGIC);
	text << "\nLoot Rate: " << g_config.getDouble(ConfigManager::RATE_LOOT);
	text << "\nProtection Level: " << g_config.getNumber(ConfigManager::PROTECTION_LEVEL);
    player->sendFYIBox(text.str().c_str());
	return true;
}

bool Commands::pvpInformation(Creature* creature, const std::string &cmd, const std::string &param)
{
	Player* player = creature->getPlayer();

	if(!player)
	{
		return false;
	}	

		int type = g_game.getWorldType();

		if (type == WORLD_TYPE_NO_PVP)
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "World type is currently set to: Optional-PvP.");
		}
		else if (type == WORLD_TYPE_PVP)
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "World type is currently set to: Open-PvP.");
		}
		else if (type == WORLD_TYPE_PVP_ENFORCED)
		{
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "World type is currently set to: Hardcore-PvP.");
		}
			
	return true;
}

bool Commands::checkMoney(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player)
		return false;

	int32_t count = atoi(param.c_str());
	uint32_t money = g_game.getMoney(player);
	if(!count)
	{
		char info[50];
		sprintf(info, "Money Information\n\nYou have %u gold.", money);
	    player->sendFYIBox(info);
		return true;
	}
	else if(count > (int32_t)money)
	{
		char info[80];
		sprintf(info, "Money Information\n\nYou have %u gold and is not sufficient.", money);
		player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, info);
		return true;
	}

	if(!g_game.removeMoney(player, count))
		player->sendCancel("Can not subtract money!");

	return true;
}

bool Commands::showWorldUpTime(Creature* creature, const std::string &cmd, const std::string &param)
{
	Player* player = creature->getPlayer();

		if(!player){
		return false;
	}	
		
    if (player->isRemoved()){ 
    return false; 
    }
	
	if (player)
	{
		uint64_t uptime = (OTSYS_TIME() - Status::getInstance()->m_start)/1000;
		int h = (int)floor(uptime / 3600.0);
		int m = (int)floor((uptime - h*3600) / 60.0);
		int s = (int)(uptime - h*3600 - m*60);

		std::stringstream msg;
		msg << "This server has been running for " << h << (h != 1? " hours " : " hour ") <<
			m << (m != 1? " minutes " : " minute ") << s << (s != 1? " seconds. " : " second.") << std::ends;

		player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, msg.str().c_str());
	}
	return true;
}

bool Commands::showNotices(Creature* creature, const std::string &cmd, const std::string &param)
{
 	 Player* player = creature->getPlayer();

	    if(!player)
		    return false;

			g_game.sendNoticeBox(g_config.getString(ConfigManager::DATA_DIRECTORY), player);
  return true;
}

bool Commands::guildJoin(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player || !g_config.getBool(ConfigManager::INGAME_GUILD_MANAGEMENT))
		return false;

	std::string param_ = param;
	trimString(param_);
	if(!player->getGuildId())
	{
		uint32_t guildId;
		if(IOGuild::getInstance()->getGuildId(guildId, param_))
		{
			if(player->isGuildInvited(guildId))
			{
				IOGuild::getInstance()->joinGuild(player, guildId);
				player->sendTextMessage(MSG_INFO_DESCR, "You have joined the guild.");

				char buffer[80];
				sprintf(buffer, "%s has joined the guild.", player->getName().c_str());
				if(ChatChannel* guildChannel = g_chat.getChannel(player, 0x00))
					guildChannel->talk(player, SPEAK_CHANNEL_RA, buffer);
			}
			else
				player->sendCancel("You are not invited to that guild.");
		}
		else
			player->sendCancel("There's no guild with that name.");
	}
	else
		player->sendCancel("You are already in a guild.");

	return true;
}

bool Commands::guildCreate(Creature* creature, const std::string& cmd, const std::string& param)
{
	Player* player = creature->getPlayer();
	if(!player || !g_config.getBool(ConfigManager::INGAME_GUILD_MANAGEMENT))
		return false;

	if(player->getGuildId())
	{
		player->sendCancel("You are already in a guild.");
		return true;
	}

	std::string param_ = param;
	trimString(param_);
	if(!isValidName(param_))
	{
		player->sendCancel("That guild name contains illegal characters, please choose another name.");
		return true;
	}

	const uint32_t minLength = g_config.getNumber(ConfigManager::MIN_GUILDNAME);
	const uint32_t maxLength = g_config.getNumber(ConfigManager::MAX_GUILDNAME);
	if(param_.length() < minLength)
	{
		player->sendCancel("That guild name is too short, please select a longer name.");
		return true;
	}

	if(param_.length() > maxLength)
	{
		player->sendCancel("That guild name is too long, please select a shorter name.");
		return true;
	}

	uint32_t guildId;
	if(IOGuild::getInstance()->getGuildId(guildId, param_))
	{
		player->sendCancel("There is already a guild with that name.");
		return true;
	}

	const uint32_t levelToFormGuild = g_config.getNumber(ConfigManager::LEVEL_TO_FORM_GUILD);
	if(player->getLevel() < levelToFormGuild)
	{
		char buffer[70 + levelToFormGuild];
		sprintf(buffer, "You have to be at least Level %d to form a guild.", levelToFormGuild);
		player->sendCancel(buffer);
		return true;
	}

	const int32_t premiumDays = g_config.getNumber(ConfigManager::GUILD_PREMIUM_DAYS);
	if(player->getPremiumDays() < premiumDays)
	{
		char buffer[70 + premiumDays];
		sprintf(buffer, "You need to have at least %d premium days to form a guild.", premiumDays);
		player->sendCancel(buffer);
		return true;
	}

	player->setGuildName(param_);
	IOGuild::getInstance()->createGuild(player);

	char buffer[50 + maxLength];
	sprintf(buffer, "You have formed guild \"%s\"!", param_.c_str());
	player->sendTextMessage(MSG_INFO_DESCR, buffer);
	return true;
}

bool Commands::whoIsOnline(Creature* creature, const std::string &cmd, const std::string &param)
{
	Player* player = creature->getPlayer();
	if(player)
	{
		std::stringstream ss;
		ss << "Players online:" << std::endl;

		uint32_t i = 0;
		AutoList<Player>::iterator it = Player::autoList.begin();
		if(!g_config.getBool(ConfigManager::SHOW_GAMEMASTERS_ONLINE))
		{
			while(it != Player::autoList.end())
			{
				if(!(*it).second->isAccessPlayer() || player->isAccessPlayer())
				{
					ss << (i > 0 ? ", " : "") << (*it).second->name << " [" << (*it).second->level << "]";
					++i;
				}
				++it;

				if(i == 10)
				{
					ss << (it != Player::autoList.end() ? "," : ".");
					player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, ss.str());
					ss.str("");
					i = 0;
				}
			}
		}
		else
		{
			while(it != Player::autoList.end())
			{
				ss << (i > 0 ? ", " : "") << (*it).second->name << " [" << (*it).second->level << "]";
				++it;
				++i;

				if(i == 10)
				{
					ss << (it != Player::autoList.end() ? "," : ".");
					player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, ss.str());
					ss.str("");
					i = 0;
				}
			}
		}

		if(i > 0)
		{
			ss << ".";
			player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, ss.str());
		}
	}
	return true;
}
